import React from 'react';

export default () => {
  // 1. 一般函数类型，返回值类型会省略
  let myAdd = function(x: number, y: number): number {
    return x + y;
  };
  // 2. 完整函数类型
  let myAdd2: (x: number, y: number) => number = function(
    x: number,
    y: number,
  ): number {
    return x + y;
  };
  // 3. 推断类型
  let myAdd3 = function(x: number, y: number): number {
    return x + y;
  };
  let myAdd4: (baseValue: number, increment: number) => number = function(
    x,
    y,
  ) {
    return x + y;
  };
  // 4. 让 ts 参数可选
  function buildName(firstName: string, lastName?: string) {
    if (lastName) return firstName + ' ' + lastName;
    else return firstName;
  }
  buildName('Bob'); // works correctly now
  // 5. 默认参数
  function buildName2(firstName = 'Will', lastName: string) {
    return firstName + ' ' + lastName;
  }

  // let result1 = buildName2("Bob");                  // error, too few parameters
  // let result2 = buildName2("Bob", "Adams", "Sr.");  // error, too many parameters
  let result3 = buildName2('Bob', 'Adams'); // okay and returns "Bob Adams"
  let result4 = buildName2(undefined, 'Adams'); // okay and returns "Will Adams"

  // 6. arguments 数组
  function buildName6(firstName: string, ...restOfName: string[]) {
    return firstName + ' ' + restOfName.join(' ');
  }

  let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;

  // 7. this
  interface Card {
    suit: string;
    card: number;
  }
  interface Deck {
    suits: string[];
    cards: number[];
    createCardPicker(this: Deck): () => Card;
  }
  let deck: Deck = {
    suits: ['hearts', 'spades', 'clubs', 'diamonds'],
    cards: Array(52),
    createCardPicker: function(this: Deck) {
      return () => {
        let pickedCard = Math.floor(Math.random() * 52);
        let pickedSuit = Math.floor(pickedCard / 13);

        return { suit: this.suits[pickedSuit], card: pickedCard % 13 };
      };
    },
  };

  let cardPicker = deck.createCardPicker();
  let pickedCard = cardPicker();

  alert('card: ' + pickedCard.card + ' of ' + pickedCard.suit);

  // 8. 重载
  let suits = ['hearts', 'spades', 'clubs', 'diamonds'];

  function pickCard(x: { suit: string; card: number }[]): number;
  function pickCard(x: number): { suit: string; card: number };
  function pickCard(x: any): any {
    // Check to see if we're working with an object/array
    // if so, they gave us the deck and we'll pick the card
    if (typeof x == 'object') {
      let pickedCard = Math.floor(Math.random() * x.length);
      return pickedCard;
    }
    // Otherwise just let them pick the card
    else if (typeof x == 'number') {
      let pickedSuit = Math.floor(x / 13);
      return { suit: suits[pickedSuit], card: x % 13 };
    }
  }

  let myDeck = [
    { suit: 'diamonds', card: 2 },
    { suit: 'spades', card: 10 },
    { suit: 'hearts', card: 4 },
  ];
  let pickedCard1 = myDeck[pickCard(myDeck)];
  alert('card: ' + pickedCard1.card + ' of ' + pickedCard1.suit);

  let pickedCard2 = pickCard(15);
  alert('card: ' + pickedCard2.card + ' of ' + pickedCard2.suit);
  return (
    <div>
      <h1>函数</h1>
      <p>
        1. TypeScript能够根据返回语句自动推断出返回值类型，因此我们通常省略它
      </p>
      <p>2. 函数和返回值类型之前使用( =>)符号</p>
      <p>
        3.
        赋值语句的一边指定了类型但是另一边没有类型的话，TypeScript编译器会自动识别出类型
      </p>
      <p>
        4. JavaScript里，每个参数都是可选的，可传可不传。
        没传参的时候，它的值就是undefined。 在TypeScript里我们可以在参数名旁使用
        ?实现可选参数的功能。
      </p>
      <p>
        5.
        所有必须参数后面的有默认初始化值的参数都是可选的，与可选参数一样。前面的就不是可选的
      </p>
      <p>
        6. 可以使用 arguments来访问所有传入的参数。
        编译器创建参数数组，名字是你在省略号（
        ...）后面给定的名字，你可以在函数体内使用这个数组
      </p>
      <p>
        7. 箭头函数能保存函数创建时的 this值，而不是调用时的值。--noImplicitThis
        需要指定 this 类型
      </p>
      <p>
        8.
        重置，为了让编译器能够选择正确的检查类型，它与JavaScript里的处理流程相似。
        它查找重载列表，尝试使用第一个重载定义。 如果匹配的话就使用这个。
        因此，在定义重载的时候，一定要把最精确的定义放在最前面
      </p>
    </div>
  );
};
